package com.offcn.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import javax.annotation.Resource;

//允许security读取相关配置
@EnableWebSecurity
//允许在controller层的方法上面添加security框架相关的注解
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //bean -- spring容器管理的对象
    @Resource
    private CustomUserDetailService userDetailService;
    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;
    @Resource
    private AccessDeniedHandler accessDeniedHandler;
    //加密对象
    @Bean
    public BCryptPasswordEncoder getPasswordEncoder(){
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder;
    }

    //认证器对象-配置
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        //捆绑两个对象 -- 底层实现返回来的数据库中的密文和前端页面输入的原始密码被加密之后形参的密文，两者对比
        auth.userDetailsService(userDetailService).passwordEncoder(getPasswordEncoder());
    }

    //全局配置
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //跨站请求伪造
        http.csrf().disable()//关闭跨站请求伪造
        //指定登录页面是谁、指定登录成功之后跳转的页面是谁
        .formLogin()//使用表单登录实现认证
        .loginPage("/login.html")//登录页面是哪个
        .loginProcessingUrl("/login")//登录连接是哪个
        .defaultSuccessUrl("/index.html")//登录成功跳转页面
        .permitAll()
        .failureHandler(authenticationFailureHandler)//登录失败如何处理
        .and()//添加其他配置
        .authorizeRequests()//请求需要认证
        //哪些资源不需要登录可以直接访问
        .antMatchers("/login.html","/login").permitAll()//代表哪些页面或者url不需要登录可以直接访问
        .antMatchers("/js/**","/css/**","/img/**","/favicon.ico").permitAll()//代表静态资源不需要登录可以直接访问
        .anyRequest()//代表当前项目任何请求都要到此处
        .authenticated();//代表需要认证

        //发生异常时如何处理
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);

        //登出 -- 退出登录的配置
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html");
    }
}
